package com.stack.wemedia.job;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.stack.apis.admin.IAdminClient;
import com.stack.common.utils.thread.WmThreadLocalUtil;
import com.stack.file.service.FileStorageService;
import com.stack.model.admin.dtos.AdNewsDto;
import com.stack.model.wemedia.dtos.WmNewsDto;
import com.stack.model.wemedia.pojos.NewsCrawler;
import com.stack.model.wemedia.pojos.WmMaterial;
import com.stack.model.wemedia.pojos.WmUser;
import com.stack.wemedia.mapper.WmMaterialMapper;
import com.stack.wemedia.service.NewsCrawlerService;
import com.stack.wemedia.service.WmNewsService;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;

/**
 * @author llz
 * @date 2024/2/5 11:42
 * @description
 */
@Component
@Slf4j
public class CrawlArticleJob {

    @Resource
    private NewsCrawlerService newsCrawlerService;
    @Resource
    private WmNewsService wmNewsService;
    @Resource
    private WmMaterialMapper wmMaterialMapper;
    @Resource
    private FileStorageService fileStorageService;
    @Resource
    private IAdminClient adminClient;

    @Resource
    private YiCar yiCar;

    @Resource
    private IFeng iFeng;

    @XxlJob("crawlHotArticleJob")
    public void jobHandler() throws IOException {

        XxlJobHelper.log("热点新闻采集任务 - 启动");
        log.info("热点新闻采集任务开始执行...");
        long startTime = System.currentTimeMillis();

        for (int i = 0; i < 5; i++) {
            // 博客园
            blog(i);
        }
        blogGetDetails();

        //直播吧
        zhiBo8();
        zhiBo8GetDetails();

        //易车
        yiCar.collectNews();

        //凤凰网
        iFeng.collectNews();

        long endTime = System.currentTimeMillis();
        log.info("热点新闻采集任务 - 结束 {}ms", (endTime - startTime));
        XxlJobHelper.log("热点新闻采集任务 - 结束 {}ms", (endTime - startTime));
    }

    private void zhiBo8GetDetails() {
        newUser();

        List<String> urls = newsCrawlerService.getUrlByChannel(1);
        for (String url : urls) {
            if (url.length() < "https://m.zhibo8.comnews".length()) {
                continue;
            }

            // 获取该网页document文档数据
            Document document = null;
            try {
                document = structureDoc(url);
            } catch (Exception e) {
                log.error("获取新闻详情失败,原因是{}", e.getMessage());
                continue;
            }

            String title = document.getElementsByClass("title").text();
            log.info("新闻的标题: {}", title);

            if (document.getElementsByClass("img_wrap").size() <= 0) {
                continue;
            }

            List<String> imgUrlList = new ArrayList<>();
            Elements imgElements = document.getElementsByClass("img_wrap");
            for (Element imgElement : imgElements) {
                String imgUrl = imgElement.attr("data");
                String fileName = uploadPic(imgUrl);
                imgUrlList.add(fileName);
            }

            // 上传图片//保存素材
            for (String imgUrl : imgUrlList) {
                WmMaterial wmMaterial = null;
                if (StringUtils.isNotBlank(imgUrl)) {
                    // 如果上传图片路径不为空  创建素材信息
                    wmMaterial = new WmMaterial();
                    wmMaterial.setUserId(WmThreadLocalUtil.getUser().getId());
                    wmMaterial.setUrl(imgUrl);
                    wmMaterial.setType((short) 0);
                    wmMaterial.setIsCollection((short) 0);
                    wmMaterial.setCreatedTime(new Date());
                    wmMaterialMapper.insert(wmMaterial);
                }
            }

            try {
                // 保存自媒体文章
                List<Map> contentMap = parseContents(document, imgUrlList);
                WmNewsDto wmNewsDto = new WmNewsDto();
                wmNewsDto.setContent(JSON.toJSONString(contentMap));
                wmNewsDto.setTitle(title);
                wmNewsDto.setType((short) 1);
                if (imgUrlList.size() > 0) {
                    List<String> imgUrls = Lists.newArrayList(imgUrlList.get(0));
                    wmNewsDto.setImages(imgUrls);
                }
                wmNewsDto.setChannelId(5);
                try {
                    Thread.sleep(1000); // 睡眠1秒 让发布时间不一致
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                wmNewsDto.setPublishTime(new Date());
                wmNewsDto.setStatus((short) 1); // 提交状态 自动审核
                wmNewsDto.setLabels("采集");
                wmNewsService.submitNews(wmNewsDto);

                // 保存admin端的相关的审核文章数据
                AdNewsDto dto = new AdNewsDto();
                dto.setUserId(WmThreadLocalUtil.getUser().getId());
                dto.setAuthorName("crawler菜鸟");
                dto.setTitle(title);
                dto.setContent(JSON.toJSONString(contentMap));
                dto.setStatus(9);
                dto.setChannelId(0);
                dto.setLabels("采集");
                dto.setCreatedTime(new Date());
                dto.setSubmitedTime(new Date());
                dto.setType(1);
                if (imgUrlList.size() > 0) {
                    List<String> imgUrls = Lists.newArrayList(imgUrlList.get(0));
                    dto.setImages(imgUrls);
                }
                dto.setEnable(0);
                log.info("保存admin端的相关的审核文章数据: {}", dto);
                adminClient.saveAdCheckNews(dto);
            } catch (Exception e) {
                log.error("保存自媒体文章失败");
                log.error("保存admin端的相关的审核文章数据失败");
                continue;
            } finally {
                //修改爬虫配置表
                NewsCrawler newsCrawler = new NewsCrawler();
                newsCrawler.setUrl(url);
                newsCrawler.setStatus(1);
                newsCrawlerService.update(newsCrawler);
            }
        }
    }



    private void zhiBo8() throws IOException {
        String url = "https://m.zhibo8.com/news.htm";
        Document document = structureDoc(url);

        Elements elements = document.getElementsByTag("h2");
        for (Element element : elements) {
            Elements tag = element.getElementsByTag("a");
            if (tag.size() == 0) {
                continue;
            }
            String newsUrl = "https://m.zhibo8.com" + tag.attr("href");
            String title = element.text();
            try {
                NewsCrawler newsCrawler = new NewsCrawler();
                newsCrawler.setTitle(title);
                newsCrawler.setUrl(newsUrl);
                newsCrawler.setChannel(1);
                newsCrawler.setStatus(0);
                newsCrawler.setCreatedTime(new Date());
                newsCrawlerService.insert(newsCrawler);
                log.info("爬爬爬爬爬爬爬!");
            } catch (Exception e) {
                log.error("标题不合规，爬取失败: {}", e.getMessage());
            }
        }
    }



    private void blogGetDetails() {
        // 模拟当前自媒体登录用户
        newUser();

        List<NewsCrawler> newsList = newsCrawlerService.getNews(2);

        for (NewsCrawler news : newsList) {
            String url = news.getUrl();
            String title = news.getTitle();
            // 获取该网页document文档数据
            Document document = null;
            Element content = null;
            try {
                document = Jsoup.connect(url).get();
                content = document.getElementsByClass("postBody").get(0);
            } catch (Exception e) {
                log.error("获取新闻详情失败,原因是{}", e.getMessage());
                continue;
            }

            Elements elements = content.getAllElements();
            List<Map> contentMap = new ArrayList<>();
            List<String> imgUrlList = new ArrayList<>();
            for (Element element : elements) {
                Map<String, String> map = null;

                try {
                    if (element.tagName().equals("p")) {
                        String text = element.text();
                        map = new HashMap<>();
                        map.put("type", "text");
                        map.put("value", text);
                        contentMap.add(map);
                    }
                    if (element.tagName().equals("img")) {
                        String imgUrl = element.attr("src");
                        String fileName = uploadPic(imgUrl);
                        imgUrlList.add(fileName);
                        map = new HashMap<>();
                        map.put("type", "image");
                        map.put("value", fileName);
                        contentMap.add(map);
                    }
                } catch (Exception e) {
                    log.error("解析失败,原因是{}", e.getMessage());
                    continue;
                }
            }

            // 上传图片//保存素材
            for (String imgUrl : imgUrlList) {
                WmMaterial wmMaterial = null;
                if (StringUtils.isNotBlank(imgUrl)) {
                    // 如果上传图片路径不为空  创建素材信息
                    wmMaterial = new WmMaterial();
                    wmMaterial.setUserId(WmThreadLocalUtil.getUser().getId());
                    wmMaterial.setUrl(imgUrl);
                    wmMaterial.setType((short) 0);
                    wmMaterial.setIsCollection((short) 0);
                    wmMaterial.setCreatedTime(new Date());
                    log.info("插入素材信息: {}", wmMaterial);
                    wmMaterialMapper.insert(wmMaterial);
                }
            }

            try {
                // 保存自媒体文章
                WmNewsDto wmNewsDto = new WmNewsDto();
                wmNewsDto.setContent(JSON.toJSONString(contentMap));
                wmNewsDto.setTitle(title);
                if (imgUrlList.size() > 0) {
                    wmNewsDto.setType((short) 1);
                    List<String> imgUrls = Lists.newArrayList(imgUrlList.get(0));
                    wmNewsDto.setImages(imgUrls);
                } else {
                    wmNewsDto.setType((short) 0);
                }

                wmNewsDto.setChannelId(1);
                try {
                    Thread.sleep(1000); // 睡眠1秒 让发布时间不一致
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                wmNewsDto.setPublishTime(new Date());
                wmNewsDto.setStatus((short) 9); //
                wmNewsDto.setLabels("采集");
                log.info("保存自媒体文章: {}", wmNewsDto);
                wmNewsService.submitNews(wmNewsDto);

                // 保存admin端的相关的审核文章数据
                AdNewsDto dto = new AdNewsDto();
                dto.setUserId(WmThreadLocalUtil.getUser().getId());
                dto.setAuthorName("crawler菜鸟");
                dto.setTitle(title);
                dto.setContent(JSON.toJSONString(contentMap));
                dto.setStatus(9);
                dto.setChannelId(1);
                dto.setLabels("采集");
                dto.setCreatedTime(new Date());
                dto.setSubmitedTime(new Date());
                if (imgUrlList.size() > 0) {
                    dto.setType(1);
                    List<String> imgUrls = Lists.newArrayList(imgUrlList.get(0));
                    dto.setImages(imgUrls);
                } else {
                    dto.setType(0);
                }
                dto.setEnable(0);
                log.info("保存admin端的相关的审核文章数据: {}", dto);
                adminClient.saveAdCheckNews(dto);
            } catch (Exception e) {
                log.error("保存自媒体文章失败:{}", e.getMessage());
                log.error("保存admin端的相关的审核文章数据失败");
            } finally {
                //修改爬虫配置表
                NewsCrawler newsCrawler = new NewsCrawler();
                newsCrawler.setUrl(url);
                newsCrawler.setStatus(1);
                newsCrawlerService.update(newsCrawler);
            }
        }
    }

    private void blog(int i) throws IOException {
        String url = "https://www.cnblogs.com/cate/java/#p" + i;
        // 获取该网页document文档数据
        Document document = structureDoc(url);
        Elements elements = document.getElementsByClass("post-item-title");
        log.info("文章url数量: {}", elements.size());
        for (Element element : elements) {
            String newsUrl = element.attr("href");
            String title = element.text();

            try {
                NewsCrawler newsCrawler = new NewsCrawler();
                newsCrawler.setTitle(title);
                newsCrawler.setUrl(newsUrl);
                newsCrawler.setChannel(2);
                newsCrawler.setStatus(0);
                newsCrawler.setCreatedTime(new Date());
                newsCrawlerService.insert(newsCrawler);
                log.info("爬爬爬爬爬爬爬!");
            } catch (Exception e) {
                log.error("标题不合规，爬取失败: {}", e.getMessage());
            }
        }
    }

    private void newUser() {
        // 模拟当前自媒体登录用户
        WmUser wmUser = new WmUser();
        wmUser.setId(1103);
        WmThreadLocalUtil.setUser(wmUser);
    }

    private Document structureDoc(String url) throws IOException {
        // 获取该网页document文档数据
        Document document = Jsoup.connect(url)
                .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36")
                .get();
        return document;
    }

    private List<Map> parseContents(Document document, List<String> imgUrlList) {
        List<Map> contentMap = new ArrayList<>();
        try {
            Elements elements = document.getElementsByTag("p");
            Map<String, String> map = null;
            String text = null;
            for (Element element : elements) {
                if (StringUtils.isNotBlank(element.text())) {
                    text = text + "\n" + element.text();
                }
            }
            map = new HashMap<>();
            map.put("type", "text");
            map.put("value", text);
            contentMap.add(map);

            for (String imgUrl : imgUrlList) {
                map = new HashMap<>();
                map.put("type", "image");
                map.put("value", imgUrl);
                contentMap.add(map);
            }
        } catch (Exception e) {
            e.printStackTrace();
            Map<String, String> map = new HashMap<>();
            map.put("type", "text");
            map.put("value", "测试文章内容");
            contentMap.add(map);
        }
        return contentMap;
    }

    /**
     * 上传图片
     * @param imgUrl
     * @return
     */
    public String uploadPic(String imgUrl) {
        String uuid = UUID.randomUUID().toString().replace("-", "");
        String suffix = imgUrl.substring(imgUrl.lastIndexOf("."));
        InputStream in = getInputStreamByUrl(imgUrl);
        if (in != null) {
            String fileName = fileStorageService.uploadImgFile("", uuid + suffix, in);
            System.out.println("上传文件名称: " + fileName);
            return fileName;
        }
        return null;
    }

    /**
     * 工具方法:  根据url路径 获取输入流
     *
     * @param strUrl
     * @return
     */
    public static InputStream getInputStreamByUrl(String strUrl) {
        HttpURLConnection conn = null;
        try {
            URL url = new URL(strUrl);
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(20 * 1000);
            final ByteArrayOutputStream output = new ByteArrayOutputStream();
            IOUtils.copy(conn.getInputStream(), output);
            return new ByteArrayInputStream(output.toByteArray());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (conn != null) {
                    conn.disconnect();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }


}
